/**
 * Copyright(c) by JNet Smartware Group.
 * All rights reserved. Not distribution or redistribution without
 * any permission of JNet Smartware Group.
 * 
 * @author thuc
 * 2010/03/15
 */
package vn.smartware.co.java.net.commons;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Class contains information about mapping between destination and source
 * property when copy from destination object to source object
 * 
 * @author thiennp
 * @author giangnh
 */
@SuppressWarnings({"rawtypes","unchecked"})
public class Properties {
	/**
	 * field prop mapping<br>
	 * each item is an instance of NameProperty
	 */
	private Map propNameMap = Collections.synchronizedMap(new HashMap());
	/**
	 * field prop value hash<br>
	 * each item is an instance of ValueProperty
	 */
	private Map propValueMap = Collections.synchronizedMap(new HashMap());

	private boolean copyAll;
	private boolean copyAllNotNull;

	/**
	 * Default constructor
	 * 
	 */
	public Properties() {
		super();
	}

	/**
	 * Add aProperty into this.propMap
	 * 
	 * @param aPropName
	 * @return instance of this class
	 */
	public Properties add(String aPropName) {
		return add(aPropName, aPropName, false);
	}
	/**
	 * Add aProperty into this.propMap
	 * 
	 * @param aPropName
	 * @return instance of this class
	 */
	public Properties addIfNotNull(String aPropName) {
		return add(aPropName, aPropName, true);
	}

	/**
	 * Add aDestProp and aSrcProp into this.propMap
	 * 
	 * @param aDestPropName
	 * @param aSrcPropName
	 * @return instance of this class
	 */
	public Properties add(String aDestPropName, String aSrcPropName) {
		return add(aDestPropName, aSrcPropName, false);
	}
	/**
	 * Add aDestProp and aSrcProp into this.propMap
	 * 
	 * @param aDestPropName
	 * @param aSrcPropName
	 * @param notCopyIfNull
	 * @return instance of this class
	 */
	private Properties add(String aDestPropName, String aSrcPropName,
			boolean notCopyIfNull) {
		if (propNameMap.containsKey(aDestPropName)) {
			throw new IllegalArgumentException("property " + aDestPropName
					+ " is duplicate");
		}

		NameProperty nameProperty = new NameProperty(aDestPropName,
				aSrcPropName, notCopyIfNull);
		propNameMap.put(aDestPropName, nameProperty);

		return this;
	}
	
	/**
	 * Add aDestProp and aSrcProp if condition is TRUE
	 * 
	 * @param condition
	 * @param aDestPropName
	 * @param aSrcPropName
	 * @return Properties
	 */
	public Properties add(boolean condition, String aDestPropName, String aSrcPropName) {
		if (condition == true) {
			return add(aDestPropName, aSrcPropName, false);
		}
		
		return this;
	}
	
	/**
	 * Add aDestProp and aSrcProp into this.propMap
	 * 
	 * @param aDestPropName
	 * @param aSrcPropName
	 * @return instance of this class
	 */
	public Properties addIfNotNull(String aDestPropName, String aSrcPropName) {
		return add(aDestPropName, aSrcPropName, true);
	}

	/**
	 * @param aPropName
	 * @param value
	 * @return instance of this class
	 */
	public Properties addValue(String aPropName, Object value) {
		return addValue(aPropName, value, false);
	}
	/**
	 * @param aPropName
	 * @param value
	 * @return instance of this class
	 */
	public Properties addValueIfNotNull(String aPropName, Object value) {
		return addValue(aPropName, value, true);
	}

	/**
	 * @param aPropName
	 * @param value
	 * @param notCopyIfNull
	 * @return instance of this class
	 */
	private Properties addValue(String aPropName, Object value,
			boolean notCopyIfNull) {
		ValueProperty valueProperty = new ValueProperty(aPropName, value,
				notCopyIfNull);
		this.propValueMap.put(aPropName, valueProperty);
		return add(aPropName, aPropName, notCopyIfNull);
	}

	/**
	 * 
	 * 
	 * @param aPropName
	 * @return value of property
	 */
	public ValueProperty getValue(String aPropName) {
		return (ValueProperty) this.propValueMap.get(aPropName);
	}
	/**
	 * Get a map of properties
	 * 
	 * @return a map of properties (destination and source property mapping)
	 */
	public Map getProperties() {
		// return new map, immutable property
		return new HashMap(this.propNameMap);
	}

	/**
	 * get property values<br>
	 * 
	 * @return Map
	 */
	public Map getPropertyValues() {
		// return new map, immutable property
		return new HashMap(this.propValueMap);
	}

	/**
	 * get property names<br>
	 * 
	 * @return only return properties spicified by name
	 */
	public Map getPropertyNames() {
		Map map = new HashMap(propNameMap);

		for (Iterator iter = propValueMap.keySet().iterator(); iter.hasNext();) {
			// remove property specified by value
			map.remove(iter.next());
		}

		return map;
	}

	/**
	 * is copy all<br>
	 * 
	 * @return boolean
	 */
	public boolean isCopyAll() {
		return this.copyAll;
	}

	/**
	 * is copy all not null<br>
	 * 
	 * @return boolean
	 */
	public boolean isCopyAllNotNull() {
		return this.copyAllNotNull;
	}

}
